const overWrite = Symbol('overWrite')
class ArrayHandle{
    static baseTypes = ["string","number","boolean","null","undefined","symbol"];
    constructor(){
        this[overWrite]();
    }
    //私有方法
    [overWrite](){
        Array.prototype.change = function(callback){
            if(typeof callback != 'function'){return new Error('${callback} is not function')}
            for(let i = 0; i<this.length; i++){
                let isDel = callback.call(this,this[i],i);
                !isDel && this.splice(i,1) && i--
            }
            return this;
        }
    }
    isBaseType(obj){
        if(ArrayHandle.baseTypes.indexOf(typeof(obj)) > -1 || (typeof obj == 'object' && obj == null)){
            return true;
        }
        return false;
    }
    isHasPro(obj,pro){
        return obj.hasOwnProperty(pro);
    }
    
    //随机打乱数组中的数据
    shuffle(arr){
        let oldIndex,tmp,len = arr.length;
        while(len){
            let index = parseInt(Math.random() * len);
            oldIndex != index &&(
                tmp = arr[len-1],
                arr[len-1] = arr[index],
                arr[index] = tmp
            )
            !oldIndex && oldIndex != 0 && (oldIndex = index)
            len--
        }
        return arr;
    };

    /**
     * 
     * @param {Array} arr 
     * @param {value,function,引用} val 
     *  var arr = ["170608",2,"a",4,"test"];
     *  var arr2 = [{name:"li",id:1},{name:'ck',id:2}]
     *  console.log(inArray(arr,3));
     *  console.log(inArray(arr2,arr2[0]));
     *  console.log(inArray(arr2,function(item,i){
     *      return item.id == 3
     *  }));
     */
    inArray(arr,val){
        if(this.isBaseType(val) || this.isPlainObject(val)){
            val = arr.indexOf(val)>-1 ? true : false;
        }else{
            //some方法：是不是至少有1个元素通过了被提供的函数测试
            //every方法：全部元素通过了被提供的函数测试
            if(typeof val != 'function'){return Error(val+' is not a function')}
            val = arr.some(val)  
        }
        return val;
    }
    //判断是否是对象字面量
    isPlainObject(obj){
        return 'isPrototypeOf' in obj && Object.prototype.toString.call(obj)==='[object Object]';
    }
    //伪数组转真
    arrayLike(arrLike){
        return Array.from ? Array.from(arrLike) : Array.prototype.slice.call(arrLike);
    }
    //生成自然数
    times(num,isIncludeZero){
        isIncludeZero = isIncludeZero||0;
        let arr = [],i = 0;
        isIncludeZero && (i = -1,isIncludeZero = -1)
        while(num>isIncludeZero){
            num--;
            arr.push(++i);
        }
        return arr;
    }
    // 快速生成自然数
    times(length){
      return Array.from({ length: length }, (v, i) => i);
    }
    //一维到二维
    toTwoArray(arr, sizes) {
        let rows = [];
        sizes = sizes || 7;
        arr = arr.concat();
        let i = 0;
        while(arr.length > 0) {
            while(i < sizes.length) {
                rows.push(arr.splice(0, sizes[i]));
                i++
            }
            if(arr.length > 0 && i == sizes.length){
                rows.push(arr.splice(0, arr.length));
            }
        }
        return rows;
    }
    //二维数组转一维
    flat(arr){
        return arr.reduce((a, b)=>{
             return a.concat(b)
        });
    }
    //数组扁平化
    flatArr(arr){
        let newArr = [];
        arr.forEach(item=>{
            if(Array.isArray(item)){
                newArr = newArr.concat(this.flatArr(item))
            }else{
                newArr.push(item);
            }
        })
        return newArr;
    }
    //此法，用到有简到繁的思想
    /**
     * 对象的扁平化
     * data:{
     *    schools:'国防'
     *    ,user:{name:['ck','陈康'],age:18,great:{'one':98,'two':100}}
     *    ,is:false
     * }
     * 
     * 结果：{'schools'：'国防','user[name][0]':'ck','user[name][1]':'陈康','age':18,'great[one]':98,'great[two]':100,'is':false}
     */
    flatObj(data){
        let target = {}
        let setItem = function(data,name){
            Object.keys(data).forEach(function(key,i){
                //将key值存储到target对象中
                let value = data[key];
                if(typeof value == 'object'){
                    key = !name && key || name+'['+key+']';
                    setItem(value,key);
                }else{
                    key = !name && key || name+'['+key+']';
                    target[key] = value
                }
            })
        };
        setItem(data);
        return target;
    }
    // flags正则修饰符
    search(str, reg, flags){
        let result = [], match;
        flags = flags || ''
        const regex = new RegExp(reg, `g${flags}`)
        while(match = regex.exec(str)){
            match.forEach((item, i) => {
                i > 0 && item && result.push(item);
            })
        }
        return result;
    }
    unflatten(obj){
        let utils = TopicTable.Utils;
        var result = {}, temp, i;
        for(let property in obj){
            //attrs = property.split('.');
            let attrs = utils.search(property,/([^\[\]]+)(?:\[([^\[\]]+)\])*?/g)
            temp = result;
            for(i = 0; i < attrs.length - 1; i++){
                let attr = attr
                if(!(attr in temp)){
                    if(isFinite(attrs[i + 1])){ 
                        temp[attr] = [];      
                    }else{
                        temp[attr] = {};      
                    }
                }
                temp = temp[attr];
            }
            temp[attrs[attrs.length - 1]] = obj[property];
        }
        return result;
    }
    //数组拼接
    arrayConcact(...arrs){
        let target = arrs.shift()
        arrs.forEach(arr=>{
            Array.prototype.push.apply(target,arr)
        })
        return target;
    }
    //获取json数组中某个字段
    getFields(jsonArr,feild) {
        jsonArr = jsonArr || [];
        return jsonArr.map(function(json){
            return json[feild]
        })
    }
    /** 
     * 获取json数组中的对象
     * getJson([{name:'ck',...},{name:'ck2',...}],{name:'ck2'})
     * getJson([{name:'ck',...},{name:'ck2',...}],function(item,i){
     *     return item.name == 'ck';
     * })  
     */
    getJson(jsonArr,rule){
        for(let i=0,len=jsonArr.length; i<len; i++){
            let item = jsonArr[i];
            if(isPlainObject(rule)){
                let key = Object.keys(rule)[0]
                if(item[key] == rule[key]){
                    return item;
                }
            }
            if(typeof rule == 'function'){
               let isTargetObj = rule.call(jsonArr,item,i);
               if(isTargetObj){
                   return item;
               }
            }
        }
    }
    //对象转数组
    objToArr(obj){
        return Object.keys(obj).map(key=>obj[key])
    }
    //是否是空数组
    isEmptyArr(arr){
        return JSON.stringify(arr) === '[]';
    }
    /**
     * 根据值删除数组中的元素
     * delValInArray([1,3,4,2,7,3,4,6,2],7)==>[1,3,4,2,3,4,6,2]
     * delValInArray([1,3,4,2,7,3,4,6,2],3,true)==>[1,4,2,4,7,6,2]
     * delValInArray([1,3,4,2,7,3,4,6,2],[3,4])==>[1,2,7,3,4,6,2]
     * delValInArray([1,3,4,2,7,3,4,6,2],[3,4],true)==>[1,2,7,6,2]
     * delValInArray([{name:'ck',...},{name:'ck2',...}],function(item,i){
     *      return item.name == 'ck';
     * })
     */
    delValInArray(arr,val,global=false){
        if(typeof val == 'function'){
            return arr.change((item,i)=>{
                return !val.call(arr,item,i);
            });
        }else{
            val = Array.isArray(val) ? val : [val];
            val.forEach(item=>{
                if(global){
                    while(arr.indexOf(item) > -1){
                        arr.splice(arr.indexOf(item),1);
                    }
                }else{
                    arr.splice(arr.indexOf(item),1);
                }
            })
            return arr;
        }
    }
    //数组去重
    //https://segmentfault.com/a/1190000011861891
    uniArr(arr,field){
        for(let i=0; i<arr.length; i++){
            for(let j=i+1; j<arr.length; j++){
                let prev = field ? arr[i][field] : arr[i];
                let next = field ? arr[j][field] : arr[j];
                prev == next && arr.splice(j,1) && j--
            }
        }
        return arr;
    }
    isArrayLike( obj ) {
        let length = !!obj && "length" in obj && obj.length;
        if(typeof obj == 'function' || (obj != null && obj === obj.window)){
            return false;
        }
        return Array.isArray(obj) || length === 0 ||
            typeof length === "number" && length > 0 && ( length - 1 ) in obj;
    }

    arrayEach(list, iterate, context) {
        for (let index = 0, len = list.length; index < len; index++) {
            const flag = iterate.call(context, list[index], index, list);
            if(flag === false) {
                break;
            }
        }
    }

    objEach(target, iterate, context) {
        for (let key in target) {
            if (target.hasOwnProperty(key)) {
                const flag = iterate.call(context, target[key], key, target);
                if(flag === false) {
                    break;
                }
            }
        }
    }

    each(target, iterate, context) {
        if(target) {
            return isArrayLike(target) ? arrayEach(target, iterate, context) : objEach(target, iterate, context);
        }
        return target;
    }
    /**
	 * 简单节点转父子树
	 * 数据格式如下：
	 * var nodes =[
		{ id:1, pId:0, name:"随意勾选 1"},
		{ id:11, pId:1, name:"随意勾选 1-1"},
		{ id:111, pId:11, name:"随意勾选 1-1-1"},
		{ id:112, pId:11, name:"随意勾选 1-1-2"},
		{ id:12, pId:1, name:"随意勾选 1-2"},
		{ id:121, pId:12, name:"随意勾选 1-2-1"},
		{ id:122, pId:12, name:"随意勾选 1-2-2"},
		{ id:2, pId:0, name:"随意勾选 2"},
		{ id:21, pId:2, name:"随意勾选 2-1"},
		{ id:22, pId:2, name:"随意勾选 2-2"},
		{ id:221, pId:22, name:"随意勾选 2-2-1"},
		{ id:222, pId:22, name:"随意勾选 2-2-2"},
		{ id:23, pId:2, name:"随意勾选 2-3"}
	   ];
    */
    parSubTree(nodes){
       var nodePoint = {},newNodes = [];
        // 删除所有 children属性,以防止多次调用
        nodes.forEach(node=>{
            delete node.children;
        });
        nodes.forEach(node=>{
            nodePoint[node.id] = node;
        });
        nodes.forEach(node=>{
            if(node.pId in nodePoint){
                (nodePoint[node.pId].children || (nodePoint[node.pId].children = [])).push(node);
            }else{//不在则是顶级节点
                newNodes.push(node);
            }
        });
        return newNodes;
    }
    /**
     * 父子树转简单节点
     * @param {*} nodes 
     * @param {*} childName 
     * @param {*} id 
     */
    parSubToSimpleTree(nodes,childName,id){
        childName = childName || 'children';
        id = id || 'id';
        // let level = 0;
        let level = 1;
        const simpleNodesFn = function(nodes,pId){
            let simpleNodes = [];
            nodes.forEach((node, i)=>{
                node.isHasChild = false;
                node.pId = pId;
                node.level = ++level;
                simpleNodes.push(node);
                let childs = node[childName]
                if(childs && childs.length>0){
                    node.isHasChild = true;
                    level++;
                    // level = 10 * level;
                    simpleNodes = simpleNodes.concat(simpleNodesFn(childs,node[id]));
                    level--;
                    // level = parseInt(level/10);
                }
            })
            return simpleNodes;
        }
        ,simpleNodes = simpleNodesFn(nodes,null);
        simpleNodes.forEach(function(node){
            node[childName] && delete node[childName];
        })
        return simpleNodes;
    }
    // 获取所有叶子节点
    leafNodes = (tree) => {
        let nodes = [];
        each(tree, (node) => {
            if(node.children && node.children.length > 0) {
                nodes = nodes.concat(leafNodes(node.children));
            }else {
                nodes.push({
                    ...node,
                    value: node.clsid,
                    label: node.clsname,
                    py: pinyin(node.clsname, {
                        pattern: 'first',
                        toneType: 'none',
                        nonZh: 'removed',
                        type: 'array'
                    }).join(''),
                });
            }
        })
        return nodes;
    }
    // 获取指定节点
    getCurNode(nodes, nodeid) {
        let curNode = null;
        each(nodes, (node, index) => {
            if(node.nodeid == nodeid) {
                curNode = node;
                return false;
            }else{
                if(node.children && node.children.length > 0) {
                    curNode = getCurNode(node.children, nodeid);
                    // 一定要加
                    if(curNode) {
                        return false;
                    }
                }
            }
        });
        return curNode;
    };
    // parentNode为可选参数
    getParentNode(nodes, curNode, parentNode) {
        each(nodes, (node, index) => {
            if(curNode != node) {
                if(nodes.length - 1 == index) {
                    parentNode = null;
                }
                if(node.children && node.children.length > 0) {
                    parentNode = page.event.getParentNode(node.children, curNode, node);
                    if(parentNode) {
                        return false;
                    }
                }
            }else{
                return false
            }
        })
        return parentNode;
    }

    //解析文件路径。类似于path.join
    pathJoin(...paths){
        let path = '';
        for(let i = paths.length - 1; i > -1; i--) {
            let pathItem = paths[i].replace(/\/+$/, '');
            // 如果是绝对路径
            if(/^\//.test(pathItem)) {
                path = pathItem + '/'+ path;
                break;
            }
            // 如果是相对路径
            if(/^\.\//.test(pathItem)) {
                pathItem = pathItem.slice(2)
            }
            // 如果是: ../../a/b/c
            if(/^(\.{2}\/)+\S+/.test(pathItem)) {
                let matches = null;
                while(matches = /^\.{2}\/(\S+)/.exec(pathItem)) {
                    pathItem = matches[1];
                    let prevPath = paths[i-1].replace(/\/+$/, '');
                    if(prevPath) {
                        paths[i-1] = prevPath.slice(0, prevPath.lastIndexOf('/'))
                    }
                }
            }
            path = pathItem + '/'+ path;
        }
        return path.replace(/\/+$/, '');
    }

    //获取全部路由的paths地址
    getPathList(routes, parentPaths = []){
        let pathList = [];
        routes.forEach(route => {
            let paths = parentPaths.concat(route.path)
            if(route.children && route.children.length > 0){
                pathList = pathList.concat(this.getPathList(route.children, paths))
            }else{
                pathList.push(paths)
            }
        })
        return pathList;
    }

    parseAllPaths(routes){
        let allPath = [];
        const pathList = this.getPathList(routes);
        pathList.forEach(paths => {
            allPath.push(this.pathJoin(...paths));
        })
        return allPath;
    }

    //获取所有路由的matches route
    getAllMatches(routes, parentRoutes = []){
        let allMatches = [];
        routes.forEach(route => {
            let matches = parentRoutes.concat(route)
            if(route.children && route.children.length > 0){
                allMatches = allMatches.concat(this.getAllMatches(route.children, matches))
            }else{
                allMatches.push(matches)
            }
        })
        return allMatches;
    }

    //根据path，匹配某个路由matches
    getRouteMatchesByPath(routes, path, parentRoutes = [], root = true){
        let allMatches = this.getAllMatches(routes);
        for(let i = 0; i< allMatches.length; i++){
            let matches = allMatches[i];
            let curPath = this.pathJoin(...matches.map(route => route.path));
            if(curPath === path){
                return matches;
            }
        }
    }
    // 根据数组索引删除
    delByIndexs(arr, callback) {
        for(const i = arr.length-1; i >= 0; i--) {
            const item = arr[i];
            if(typeof callback == 'function') {
                const isDel = callback(item, i);
                isDel && arr.splice(i, 1);
            }
        }
        return arr;
    }

    // 删除对象无效
    delKeys(deep, target, callback) {
        typeof deep !== 'boolean' && (
            callback = target,
            target = deep,
            deep = false
        )
        const keys = Object.keys(target);
        for(let i = keys.length - 1; i >= 0; i--) {
            const key = keys[i];
            const value = target[key];
            const isDel = callback(value, key, target);
            if(isDel === true) {
                if(target instanceof Array){
                    target.splice(Number(key), 1)
                }else{
                    Reflect.deleteProperty(target, key);
                }
            }else{
                if (typeof value == "object" && value != null && deep) {
                    target[key] = filterKeys(deep, value, callback)
                }
            }
        }
        return target;
    }

    // 过滤不包含keys的键
    filterKeys(target, keys) {
        return Object.keys(target).reduce((newData, key) => {
            if (!keys.includes(key)) {
              newData[key] = target[key];
            }
            return newData;
        }, {});
    }

    // 获取指定数量的键
    inKeys(target, keys) {
        return Object.keys(target).reduce((newData, key) => {
            if (keys.includes(key)) {
              newData[key] = target[key];
            }
            return newData;
        }, {});
    }

}